<script setup>
import Toast from '@vant/weapp/dist/toast/toast';
import myCanvas from '@/utils/myCanvas.js'
import { ref, nextTick, getCurrentInstance, onMounted, watch } from 'vue';

import { onLoad, onReady } from '@dcloudio/uni-app';


// 画布比例数组
const sizeList = ref([
    {
        id: 1,
        iconfont: "ai-icon-Frame2",
        content: "原图",
    },
    {
        id: 2,
        iconfont: "ai-icon-a-1_1",
        content: "1:1",
    },
    {
        id: 3,
        iconfont: "ai-icon-a-3_4",
        content: "3:4",
    },
    {
        id: 4,
        iconfont: "ai-icon-a-4_3",
        content: "4:3",
    },
    {
        id: 5,
        iconfont: "ai-icon-a-3_4",
        content: "9:16",
    },
    {
        id: 6,
        iconfont: "ai-icon-a-16_9",
        content: "16:9",
    },
]);


// 页面参数
const queryParams = ref({
    imageFileUrl: '',
    scale: 1,
    size: sizeList.value[0].content,
})
// 提交参数
const queryData = ref({
    imageFileUrl: '',
})



// 父盒子宽高
const contentDom = ref({})

// 图片宽高(用于canvas)
const imgRect = ref({
    width: 0,
    height: 0
})
// 图片原始尺寸(用于提交时)
const oldImgRect = ref({
    width: 0,
    height: 0
})


let rectCanvas, imgCanvas

const rectAndImgCanvas = ref({
    dx: 0,
    dy: 0,
    width: 0,
    height: 0,
})

let startX = 0;
let startY = 0;
let initialDistance = 0;
let initialScale = queryParams.value.scale;

// 是否正在双指绘图
const twoMove = ref(false)

// 开始生成
async function createFn() {
    await exportCanvasImage()
    let pages = getCurrentPages()
    let prevPage = pages[pages.length - 2]
    prevPage.$vm.setImageFileUrl(queryData.value.imageFileUrl)
    uni.navigateBack()
}

// 获取屏幕像素密度
function getPixelRatio() {
    return uni.getSystemInfoSync().pixelRatio;
}




// 导出canvas图片
function exportCanvasImage() {
    return new Promise(resolve => {
        uni.canvasToTempFilePath({
            canvas: imgCanvas.canvas,
            x: rectAndImgCanvas.value.dx + 4,
            y: rectAndImgCanvas.value.dy + 4,
            width: rectAndImgCanvas.value.width - 4,
            height: rectAndImgCanvas.value.height - 8,
            success(res) {
                console.log(res.tempFilePath, '导出图片成功');
                queryData.value.imageFileUrl = res.tempFilePath
                resolve()
            },
            fail(err) {
                console.log(err, '导出图片失败');
                Toast.fail('导出图片失败')
            },
        })
    })
}



// 根据选中的宽高比计算图片的宽高
// 传入图片宽高和选中宽高比，返回新的宽高
function getAspectRatioFn(val) {
    const { width, height, ratio } = val

    let maxWidth = width > height

    let newRatio = ratio.split(':') // 宽newRatio[0],高：newRatio[1] 传入选中宽高比

    let aspectRatio = (Math.ceil((newRatio[0] / newRatio[1]) * 100) / 100).toFixed(2) // 传入宽高比

    let imgAspectRatio = (Math.ceil((width / height) * 100) / 100).toFixed(2) // 图片宽高比

    let imgRact = {
        width: '',
        height: ''
    }
    if (maxWidth) { // 宽

        if (imgAspectRatio > aspectRatio) { // 图片宽高比大于选择的比例

            imgRact.height = (width / newRatio[0]) * newRatio[1]
            imgRact.width = width

        } else if (imgAspectRatio < aspectRatio) {

            imgRact.width = (height / newRatio[1]) * newRatio[0]
            imgRact.height = height
        } else {
            imgRact.width = width
            imgRact.height = height
        }
    } else {  // 高
        if (imgAspectRatio > aspectRatio) {

            imgRact.height = (width / newRatio[0]) * newRatio[1]
            imgRact.width = width

        } else if (imgAspectRatio < aspectRatio) {

            imgRact.width = (height / newRatio[1]) * newRatio[0]
            imgRact.height = height
        } else {
            imgRact.width = width
            imgRact.height = height
        }

    }
    return imgRact
}

// 尺寸点击事件
function sizeItemClick(item) {
    queryParams.value.size = item.content;
    initialDistance = 0;
    initialScale = 0;
    queryParams.value.scale = 1;

    if (item.id === 1) {
        rectAndImgCanvas.value.width = oldImgRect.value.width;
        rectAndImgCanvas.value.height = oldImgRect.value.height;
    } else {
        const radioInfo = getAspectRatioFn({
            width: oldImgRect.value.width,
            height: oldImgRect.value.height,
            ratio: item.content,
        });

        const widthRatio = contentDom.value.width / radioInfo.width;
        const heightRatio = contentDom.value.height / radioInfo.height;
        const scaleRatio = Math.min(widthRatio, heightRatio);

        rectAndImgCanvas.value.width = radioInfo.width * scaleRatio;
        rectAndImgCanvas.value.height = radioInfo.height * scaleRatio;
    }

    const canvasWidth = contentDom.value.width;
    const canvasHeight = contentDom.value.height;

    nextTick(() => {
        rectAndImgCanvas.value.dx = (canvasWidth - rectAndImgCanvas.value.width) / 2;
        rectAndImgCanvas.value.dy = (canvasHeight - rectAndImgCanvas.value.height) / 2;


        rectCanvas.drawBorderedRect(
            rectAndImgCanvas.value.dx,
            rectAndImgCanvas.value.dy,
            rectAndImgCanvas.value.width,
            rectAndImgCanvas.value.height,
            {
                borderColor: '#FFF',
                backgroundImage: 'https://devweb.topyunliu.com/upload/2025/03/30/file_20250330134701A002.png',
                drawImgBefore: () => {
                    rectCanvas.clearRect(0, 0, contentDom.value.width, contentDom.value.height);
                    rectCanvas.ctx.beginPath();
                    rectCanvas.ctx.rect(rectAndImgCanvas.value.dx, rectAndImgCanvas.value.dy, rectAndImgCanvas.value.width, rectAndImgCanvas.value.height);
                    rectCanvas.ctx.lineWidth = 2;
                    rectCanvas.ctx.strokeStyle = '#FFF';
                    rectCanvas.ctx.stroke();
                    rectCanvas.ctx.closePath();
                }
            }
        );

        imgCanvas.drawBorderedRect(
            rectAndImgCanvas.value.dx,
            rectAndImgCanvas.value.dy,
            rectAndImgCanvas.value.width,
            rectAndImgCanvas.value.height,
            {
                borderColor: 'transparent',
                backgroundColor: 'transparent',
            }
        );

        const imgAspectRatio = oldImgRect.value.width / oldImgRect.value.height;
        const canvasAspectRatio = rectAndImgCanvas.value.width / rectAndImgCanvas.value.height;

        if (imgAspectRatio > canvasAspectRatio) {
            imgRect.value.width = rectAndImgCanvas.value.width;
            imgRect.value.height =
                (rectAndImgCanvas.value.width / oldImgRect.value.width) * oldImgRect.value.height;
        } else {
            imgRect.value.height = rectAndImgCanvas.value.height;
            imgRect.value.width =
                (rectAndImgCanvas.value.height / oldImgRect.value.height) * oldImgRect.value.width;
        }

        imgRect.value.dx = (rectAndImgCanvas.value.width - imgRect.value.width) / 2 + rectAndImgCanvas.value.dx;
        imgRect.value.dy = (rectAndImgCanvas.value.height - imgRect.value.height) / 2 + rectAndImgCanvas.value.dy;

        imgCanvas.drawImage(
            queryParams.value.imageFileUrl,
            imgRect.value.dx,
            imgRect.value.dy,
            imgRect.value.width,
            imgRect.value.height,
            () => {
                imgCanvas.clearRect(0, 0, contentDom.value.width, contentDom.value.height);
                // 保存画布状态（裁剪前）
                imgCanvas.ctx.save();
                imgCanvas.ctx.clip();
            },
            () => {
                // 恢复画布状态（移除裁剪区域）
                imgCanvas.ctx.restore();
                Toast.clear()
            }
        );
    });
}






// 获取双指间距
function getDistance(touches) {
    const dx = touches[1].clientX - touches[0].clientX;
    const dy = touches[1].clientY - touches[0].clientY;
    return Math.sqrt(dx * dx + dy * dy);
}


// 边界判定方法
function calculateBoundary(newDx, newDy, imgWidth, imgHeight) {
    const minDx = rectAndImgCanvas.value.dx;
    const maxDx = rectAndImgCanvas.value.dx + rectAndImgCanvas.value.width - imgWidth;
    const minDy = rectAndImgCanvas.value.dy;
    const maxDy = rectAndImgCanvas.value.dy + rectAndImgCanvas.value.height - imgHeight;

    return {
        dx: Math.min(Math.max(newDx, minDx), maxDx),
        dy: Math.min(Math.max(newDy, minDy), maxDy),
    };
}


// 手指按下事件
function touchstart(event) {
    if (event.touches.length === 1) {
        twoMove.value = false
        const touch = event.touches[0];
        startX = touch.clientX - imgRect.value.dx;
        startY = touch.clientY - imgRect.value.dy;
    } else if (event.touches.length === 2) {
        twoMove.value = true
        initialDistance = getDistance(event.touches);
        initialScale = queryParams.value.scale;
    }
}

// 手指移动事件
function touchmove(event) {
    imgCanvas.ctx.save()
    if (event.touches.length === 1) {
        if (twoMove.value) return

        const touch = event.touches[0];
        let newDx = touch.clientX - startX;
        let newDy = touch.clientY - startY;

        const imgWidth = imgRect.value.width * queryParams.value.scale;
        const imgHeight = imgRect.value.height * queryParams.value.scale;

        const boundary = calculateBoundary(newDx, newDy, imgWidth, imgHeight);
        // imgRect.value.dx = boundary.dx;
        // imgRect.value.dy = boundary.dy;
        imgRect.value.dx = newDx;
        imgRect.value.dy = newDy;
    } else if (event.touches.length === 2) {
        const currentDistance = getDistance(event.touches);
        const scaleChange = currentDistance / initialDistance;
        const newScale = Math.min(2, Math.max(0.5, initialScale * scaleChange));

        const imgWidth = imgRect.value.width * newScale;
        const imgHeight = imgRect.value.height * newScale;

        const newDx = imgRect.value.dx + (imgRect.value.width * (queryParams.value.scale - newScale)) / 2;
        const newDy = imgRect.value.dy + (imgRect.value.height * (queryParams.value.scale - newScale)) / 2;

        const boundary = calculateBoundary(newDx, newDy, imgWidth, imgHeight);
        // imgRect.value.dx = boundary.dx;
        // imgRect.value.dy = boundary.dy;
        imgRect.value.dx = newDx;
        imgRect.value.dy = newDy;

        queryParams.value.scale = newScale;
    }

    const imgWidth = imgRect.value.width * queryParams.value.scale;
    const imgHeight = imgRect.value.height * queryParams.value.scale;

    imgCanvas.drawImage(
        queryParams.value.imageFileUrl,
        imgRect.value.dx,
        imgRect.value.dy,
        imgWidth,
        imgHeight,
        () => {
            imgCanvas.clearRect(0, 0,
                contentDom.value.width,
                contentDom.value.height);
            imgCanvas.ctx.clip()
        },
        () => {
            imgCanvas.ctx.restore()
        }
    );
}
// function touchmove(event) {
//     imgCanvas.ctx.save()
//     if (event.touches.length === 1) {
//         if (twoMove.value) return

//         const touch = event.touches[0];
//         imgRect.value.dx = touch.clientX - startX;
//         imgRect.value.dy = touch.clientY - startY;
//     } else if (event.touches.length === 2) {
//         const currentDistance = getDistance(event.touches);
//         const scaleChange = currentDistance / initialDistance;
//         queryParams.value.scale = Math.min(3, Math.max(0.1, initialScale * scaleChange));
//     }

//     const imgWidth = imgRect.value.width * queryParams.value.scale;
//     const imgHeight = imgRect.value.height * queryParams.value.scale;

//     imgCanvas.drawImage(
//         queryParams.value.imageFileUrl,
//         imgRect.value.dx,
//         imgRect.value.dy,
//         imgWidth,
//         imgHeight,
//         () => {
//             imgCanvas.clearRect(0, 0,
//                 contentDom.value.width,
//                 contentDom.value.height);
//             imgCanvas.ctx.clip()
//         },
//         () => {
//             imgCanvas.ctx.restore()
//         }
//     );
// }



// 绘制图片
function drawImageFn() {
    nextTick(() => {
        rectCanvas.init();
        imgCanvas.init();
        setTimeout(() => {

            // 外层矩形绘制位置
            rectAndImgCanvas.value = {
                dx: (contentDom.value.width - imgRect.value.width) / 2,
                dy: (contentDom.value.height - imgRect.value.height) / 2,
                width: imgRect.value.width,
                height: imgRect.value.height,
            }
            rectCanvas.drawBorderedRect(rectAndImgCanvas.value.dx, rectAndImgCanvas.value.dy,
                rectAndImgCanvas.value.width,
                rectAndImgCanvas.value.height,
                {
                    borderColor: '#FFF',
                    backgroundImage: 'https://devweb.topyunliu.com/upload/2025/03/27/file_20250327183317A001.jpeg'
                });
            imgCanvas.drawBorderedRect(rectAndImgCanvas.value.dx, rectAndImgCanvas.value.dy,
                rectAndImgCanvas.value.width,
                rectAndImgCanvas.value.height,
                {
                    borderColor: 'transparent',
                    backgroundColor: 'transparent'
                });
            // 保存画布状态（裁剪前）
            imgCanvas.ctx.save()

            imgCanvas.ctx.clip()

            imgRect.value.dx = (contentDom.value.width - imgRect.value.width) / 2;
            imgRect.value.dy = (contentDom.value.height - imgRect.value.height) / 2;

            imgCanvas.drawImage(
                queryParams.value.imageFileUrl,
                imgRect.value.dx,
                imgRect.value.dy,
                imgRect.value.width,
                imgRect.value.height
            );
            // // 3. 恢复画布状态（移除裁剪区域）
            imgCanvas.ctx.restore();
        }, 1000);
    });
}



// 计算图片宽高比及外部边框盒子的宽高
async function calculatePicAspectRatio(path) {
    const { width, height } = await uni.getImageInfo({ src: path })

    const widthRatio = contentDom.value.width / width;
    const heightRatio = contentDom.value.height / height;
    const scaleRatio = Math.min(widthRatio, heightRatio);

    // 计算缩放后的图片宽度和高度
    const scaledWidth = width * scaleRatio;
    const scaledHeight = height * scaleRatio;

    // 绘制尺寸
    imgRect.value = {
        width: scaledWidth,
        height: scaledHeight
    }
    // 基准尺寸
    oldImgRect.value = {
        width: scaledWidth,
        height: scaledHeight
    }
}


// 相册选择
function uploadImgFn() {
    uni.chooseImage({
        count: 1,
        success: (res) => {
            queryParams.value.imageFileUrl = res.tempFilePaths[0]
            calculatePicAspectRatio(queryParams.value.imageFileUrl).then(() => {
                // drawImageFn()
                const item = sizeList.value.find(item => {
                    return item.content === queryParams.value.size
                })
                sizeItemClick(item)
            })
        }
    })
}


onReady(() => {
    uni.createSelectorQuery().select('.canvas_box').boundingClientRect((res) => {
        // canvas宽高
        contentDom.value.width = res.width
        contentDom.value.height = res.height
        rectCanvas = new myCanvas('rectCanvas')
        imgCanvas = new myCanvas('imgCanvas')
    }).exec()
})


onLoad((e) => {
    Toast.loading({
        message: '图片处理中...',
        duration: 0,
    });
    if (e.item) {
        queryParams.value.imageFileUrl = JSON.parse(e.item).imageFileUrl
        nextTick(() => {
            setTimeout(() => {
                calculatePicAspectRatio(queryParams.value.imageFileUrl).then(() => {
                    const item = sizeList.value.find(item => {
                        return item.content === queryParams.value.size
                    })
                    sizeItemClick(item)
                })
            }, 300);
        })
    }
})
</script>

<template>
    <div class='expansionPicture'>
        <NavBar>图片调整</NavBar>
        <div class="container">
            <div class="canvas_box">
                <div class="uploadImgBtn" @click="uploadImgFn" v-if="!queryParams.imageFileUrl">
                    <i class="iconfont ai-icon-xiangcexuanze"></i>
                    相册选择
                </div>
                <canvas type="2d" id="rectCanvas" class="rectCanvas"></canvas>
                <canvas type="2d" id="imgCanvas" class="imgCanvas" @touchstart="touchstart"
                    @touchmove.stop="touchmove"></canvas>
            </div>
        </div>

        <div class="footer">
            <div class="footer_placeholder"></div>
            <div class="footer_content">
                <div class="footer_top">
                    <div class="uploadImg" @click="uploadImgFn" v-if="queryParams.imageFileUrl">
                        <i class="iconfont ai-icon-shangchuan"></i>
                        <div>上传图片</div>
                    </div>
                </div>
                <div class="footer_center">
                    <div class="size_list">
                        <div class="size_item" :class="{ active: queryParams.size === item.content }"
                            v-for="item of sizeList" @click="sizeItemClick(item)">
                            <i :class="`iconfont ${item.iconfont}`"></i>
                            <div class="text">{{ item?.content }}</div>
                        </div>
                    </div>

                </div>

                <div class="create_btn" @click="createFn">
                    <div class="create_btn_title">保存图片</div>
                </div>
            </div>
        </div>
    </div>
    <van-toast id="van-toast" />
</template>

<style lang='scss' scoped>
.expansionPicture {
    height: 100vh;
    display: flex;
    flex-direction: column;

    .container {
        box-sizing: border-box;
        flex: 1;

        .canvas_box {
            position: relative;
            width: 100%;
            height: 100%;
            overflow: hidden;

            .uploadImgBtn {
                position: absolute;
                top: 50%;
                left: 50%;
                z-index: 10;
                transform: translate(-50%, -50%);
                width: 228rpx;
                height: 84rpx;
                border-radius: 45rpx;
                background-color: transparent;
                border: 3rpx solid var(--a-main-color);
                color: var(--a-one-text-color);
                display: flex;
                align-items: center;
                justify-content: center;
                gap: 10rpx;
            }

            .rectCanvas,
            .imgCanvas {
                position: absolute;
                top: 50%;
                left: 50%;
                transform: translate(-50%, -50%);
                width: 100%;
                height: 100%;
            }

            .rectCanvas {
                z-index: 1;
            }

            .imgCanvas {
                z-index: 2;
            }

        }
    }

    .footer {
        .footer_placeholder {
            height: 400rpx;
        }

        .footer_content {
            box-sizing: border-box;
            position: fixed;
            left: 0;
            bottom: 0;
            width: 100%;
            height: 400rpx;
            background: var(--a-main-tabNav-bg-color);
            padding: 30rpx;

            .footer_top {
                position: relative;

                .uploadImg {
                    position: absolute;
                    left: 0;
                    top: -10rpx;
                    font-size: 20rpx;
                    text-align: center;
                    color: var(--a-two-text-color);
                }
            }

            .footer_center {
                margin-top: 60rpx;

                .slider_box {
                    padding-top: 40rpx;

                    .slider_content {
                        box-sizing: border-box;
                        position: relative;
                        padding: 0 50rpx;

                        .slider_btn {
                            width: 50rpx;
                            height: 50rpx;
                            line-height: 50rpx;
                            border-radius: 50%;
                            background-color: var(--a-main-color);
                            border: 5rpx solid #FFF;
                            position: relative;
                            color: var(--a-main-Feature-text-color);
                            font-size: 24rpx;
                            text-align: center;
                        }
                    }


                    .num_box {
                        display: flex;
                        align-items: center;
                        justify-content: space-between;
                        font-size: 25rpx;
                        color: #C2C2C2;
                        font-weight: bold;
                        margin-top: 30rpx;
                    }
                }

                .size_list {
                    display: flex;
                    align-items: center;
                    gap: 20rpx;
                    overflow: scroll;

                    &::-webkit-scrollbar {
                        display: none;
                    }

                    .size_item {
                        box-sizing: border-box;
                        flex-shrink: 0;
                        width: 100rpx;
                        height: 120rpx;
                        border-radius: 12rpx;
                        border: 3rpx solid transparent;
                        background: var(--a-main-box-bg-color);
                        overflow: hidden;
                        display: flex;
                        flex-direction: column;
                        justify-content: space-around;
                        align-items: center;
                        font-size: 22rpx;
                        color: var(--a-one-text-color);

                        .iconfont {
                            font-size: 34rpx;
                        }

                        &.active {
                            color: var(--a-main-color);
                            border: 3rpx solid var(--a-main-color);
                        }
                    }
                }
            }

            .create_btn {
                height: 86rpx;
                background: var(--a-main-color);
                border-radius: 44rpx;
                display: flex;
                flex-direction: column;
                align-items: center;
                justify-content: center;
                margin-top: 30rpx;

                .create_btn_title {
                    font-size: 32rpx;
                    color: var(--a-one-text-color);
                }

                .create_btn_label {
                    font-size: 20rpx;
                    color: var(--a-one-text-color);
                }
            }
        }
    }
}
</style>